<template>
  <div class="pdf-marking">
    <div class="pdf-marking-content" ref="pdfMarkingContent">
      <div class="toolbox-box" v-show="!hideToolbox">
        <div class="toolbox-items">
          <Button name="panel" class="toggleLeftButton" :active="LeftPanelShow" @click="toggleLeftPanel()"/>
          <div class="divider"></div>
          <Button name="pan" :active="pointerType==='hand'" @click="setPointerType('hand')"/>
          <Button name="select" :active="pointerType==='select'" @click="setPointerType('select')"/>
          <Button name="zoomout" @click="zoomout"/>
          <Button name="zoomin" @click="zoomin"/>
          <!--@mousedown.stop @touchstart.stop-->
          <div class="zoomOverlayButton"
               :class="{active:ZoomOverlayShow}"
               ref="zoomOverlayButton"
               @click="toggleZoomOverlay">
            <div class="OverlayText">
              <input type="text" tabindex="-1" :value="Math.round(scale*100)"
                     @keydown="handleScaleKeyDown"
                     @keyup="handleScaleKeyUp"
                     @keypress.enter="handleScaleEnter">
              <span>%</span>
            </div>
            <div class="Button">
              <div class="Icon ">
                <svg viewBox="-10 -15 51 49" version="1.1" xmlns="http://www.w3.org/2000/svg"
                     xmlns:xlink="http://www.w3.org/1999/xlink">
                  <title>Triangle</title>
                  <desc>Created with Sketch.</desc>
                  <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
                    <g id="Artboard" transform="translate(0.000000, -3.000000)" fill="#000000">
                      <polygon id="Triangle"
                               transform="translate(12.000000, 12.000000) scale(1, -1) translate(-12.000000, -12.000000) "
                               points="12 3 24 21 0 21"></polygon>
                    </g>
                  </g>
                </svg>
              </div>
            </div>
          </div>
          <!--<Button :config="btn" v-for="(btn,idx) in btnList" :key="idx"/>-->
          <div style="flex: 1"></div>
          <Button name="highlight" type="hasStyles"
                  :active="pointerType==='highlight'"
                  class="ToolButton"
                  :activeColor="pointerConfig['highlight'].fill"
                  @click="handleButtonClick($event,'highlight')"/>
          <Button name="freeLine" type="hasStyles"
                  :active="pointerType==='freeLine'"
                  class="ToolButton"
                  :activeColor="pointerConfig['freeLine'].stroke"
                  @click="handleButtonClick($event,'freeLine')"/>
          <Button name="line" type="hasStyles"
                  :active="pointerType==='line'"
                  class="ToolButton"
                  :activeColor="pointerConfig['line'].stroke"
                  @click="handleButtonClick($event,'line')"/>
          <Button name="rect" type="hasStyles"
                  :active="pointerType==='rect'"
                  class="ToolButton"
                  :activeColor="pointerConfig['rect'].stroke"
                  @click="handleButtonClick($event,'rect')"/>
          <Button name="ellipse" type="hasStyles"
                  :active="pointerType==='ellipse'"
                  class="ToolButton"
                  :activeColor="pointerConfig['ellipse'].stroke"
                  @click="handleButtonClick($event,'ellipse')"/>
          <Button name="arrow" type="hasStyles"
                  :active="pointerType==='arrow'"
                  class="ToolButton"
                  :activeColor="pointerConfig['arrow'].stroke"
                  @click="handleButtonClick($event,'arrow')"/>
          <!--<Button name="freeText" type="hasStyles"-->
          <!--        :active="pointerType==='freeText'"-->
          <!--        class="ToolButton"-->
          <!--        :activeColor="pointerConfig['freeText'].text"-->
          <!--        @click="handleButtonClick($event,'freeText')"/>-->
          <Button name="eraser" :active="pointerType==='eraser'" @click="setPointerType('eraser')"/>
          <div class="divider"></div>
          <Button name="search"
                  :active="SearchOverlayShow"
                  class="SearchOverlayButton"
                  ref="SearchOverlayButton"
                  @click="toggleSearchOverlay"/>
        </div>
        <!--<div class="tooltip&#45;&#45;bottom" style="opacity: 1; top: 46px; left: 535.151px;">-->
        <!--  <div class="tooltip__content">Freehand tools</div>-->
        <!--</div>-->
      </div>
      <div class="DocumentContainerBox"
           :class="{'right-panel':SearchPanelShow,'left-panel':LeftPanelShow}">
        <div class="DocumentContainer"
             ref="DocumentContainer"
             @contextmenu.prevent="handleDocumentContainerContextmenu"
             @wheel="handleDocumentContainerWheel"
             @scroll="handleScroll" :style="DocumentContainerStyle">
          <vue-resize-sensor initial @resize="handleViewSizeChange"/>
          <div class="document" tabindex="-1" :style="{width: `${(maxImageWidth + 2 * 4) * scale}px`}">
            <div :id="`pageSection${data.pageIndex}`" v-for="data in dataShowList"
                 :key="data.pageIndex" class="pageSection"
                 ref="pageSection"
                 :style="{
                position: `relative`,
                width: `${maxImageWidth*scale}px`,
                height: `${data.imgSize.height*scale}px`,
                margin: `${4*scale}px`,
             }">
              <page-container :data="data"
                              ref="pageContainer"
                              v-if="data.pageIndex>currPageIndex-pageCount/2&&data.pageIndex<currPageIndex+pageCount/2"/>
              <div class="pageSection__watermark"
                   :style="{zoom:scale}">
                <slot name="watermark" :imgSize="data.imgSize" :pageIndex="data.pageIndex"></slot>
              </div>
            </div>
          </div>
        </div>
        <div class="Popup TextPopup" :class="TextPopupShow?'open':'closed'"
             ref="TextPopup" @mousedown.stop @touchstart.stop>
          <component :is="item.component" v-show="!~textpopupDisableelement.indexOf(item.props.name)"
                     @click="handleTextPopupButtonClick($event,item)" v-bind="item.props"
                     v-for="(item,idx) in TextPopupButtonList" :key="idx"/>
        </div>
        <div class="Popup ContextMenuPopup" :class="!hideContextmenupopup&&ContextMenuPopupShow?'open':'closed'"
             ref="ContextMenuPopup" @mousedown.stop @touchstart.stop>
          <component :is="item.component" v-show="!~contextmenupopupDisableelement.indexOf(item.props.name)"
                     @click="handleContextMenuPopupButtonClick($event,item)" v-bind="item.props"
                     v-for="(item,idx) in ContextMenuPopupButtonList" :key="idx"/>
        </div>
        <div class="Popup AnnotationPopup closed" style="left: 344px; top: 432px;">
          <Button name="delete"/>
        </div>
      </div>
      <div class="Panel LeftPanel" :class="LeftPanelShow?'open':'closed'">
        <div class="left-panel-header">
          <!--<div class="close-btn hide-in-desktop">-->
          <!--  <div class="Icon ">-->
          <!--    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">-->
          <!--      <path d="m0 0h24v24h-24z" fill="none"></path>-->
          <!--      <path-->
          <!--        d="m19 6.41-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"></path>-->
          <!--    </svg>-->
          <!--  </div>-->
          <!--</div>-->
          <div class="LeftPanelTabs">
            <Button name="thumbnailsPanel" @click="LeftPanelTabType='thumbnails'"
                    :active="LeftPanelTabType==='thumbnails'"/>
            <!--<Button name="outlinesPanel"/>-->
            <Button name="notesPanel" @click="LeftPanelTabType='annotations'"
                    :active="LeftPanelTabType==='annotations'"/>
            <!--<Button name="bookmarksPanel"/>-->
          </div>
        </div>
        <div class="resize-bar"></div>
        <div class="Panel ThumbnailsPanel" v-if="LeftPanelShow&&LeftPanelTabType==='thumbnails'">
          <div class="virtualized-thumbnails-container">
            <div class="Thumbnail" ref="Thumbnail" @click="skipPage(data.pageIndex)"
                 :class="{active:currPageIndex===data.pageIndex}"
                 v-for="data in dataList"
                 :key="data.pageIndex">
              <div class="container">
                <!--<div class="thumbnail">-->
                <v-stage class="thumbnail" :config="{
                  scale:{
                    x:Math.min(115/data.imgSize.width,150/data.imgSize.height),
                    y:Math.min(115/data.imgSize.width,150/data.imgSize.height)
                  },
                  width: 115,
                  height: 150}">
                  <v-layer>
                    <v-image :config="{image:data.img,preventDefault:false,
                    x:(115/Math.min(115/data.imgSize.width,150/data.imgSize.height)-data.imgSize.width)/2,
                    y:(150/Math.min(115/data.imgSize.width,150/data.imgSize.height)-data.imgSize.height)/2,
                    }"/>
                  </v-layer>
                </v-stage>
                <!--<canvas width="172" height="225" class="page-image"-->
                <!--        style="width: 115px; height: 150px; background-color: white; max-width: 150px; max-height: 150px;"></canvas>-->
                <!--<canvas class="annotation-image" width="116" height="150"-->
                <!--        style="max-width: 150px; max-height: 150px;"></canvas>-->
                <!--</div>-->
              </div>
              <div class="page-label">{{data.pageIndex+1}}</div>
            </div>
            <div class="no-data" v-show="!dataList.length">
              <div>没有打开文档</div>
            </div>
          </div>
        </div>
        <div class="Panel NotesPanel" v-show="LeftPanelTabType==='annotations'">
          <div class="normal-notes-container">
            <div class="note-wrapper" v-for="item in annotationShowList"
                 :key="item.pageIndex">
              <div class="ListSeparator">第 {{item.pageIndex+1}} 页</div>
              <div class="Note" @click="skipPage(item.pageIndex)" v-for="annoItem in item.list"
                   :key="annoItem.relationId">
                <div class="NoteContent">
                  <div class="title">
                    <div class="type">
                      <Button class="disable" :name="annoItem.pointerType" :color="annoItem.color"/>
                    </div>
                    <!--<span>Guest</span>-->
                    <span class="spacer"></span>
                    <div class="time">{{annoItem.createTime}}</div>
                    <div class="fill-width"></div>
                    <div class="del-btn" title="删除"
                         @click.stop="handleAnnotationListDeleteBtnClick(annoItem.relationId)">
                      <Button name="delete"/>
                    </div>
                  </div>
                  <div class="content-container">
                    <!--<div class="container">-->
                    <!--  <span class="contents">-->
                    {{annoItem.text}}
                    <!--  </span>-->
                    <!--</div>-->
                  </div>
                </div>
              </div>
            </div>
            <div class="no-data" v-show="!annotationShowList.length">
              <div>该文档没有任何注释</div>
            </div>
          </div>
        </div>
        <!--<div class="Panel OutlinesPanel">-->
        <!--  <div class="no-outlines">This document has no outline.</div>-->
        <!--</div>-->
        <!--<div class="Panel BookmarksPanel" data-element="bookmarksPanel" style="display: none;">-->
        <!--  <div class="bookmarks-panel-header ">-->
        <!--    <div class="bookmarks-panel-container">-->
        <!--      <div class="Icon ">-->
        <!--        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">-->
        <!--          <path d="m0 0h24v24h-24z" fill="none"></path>-->
        <!--          <path d="m17 3h-10c-1.1 0-1.99.9-1.99 2l-.01 16 7-5 7 5v-16c0-1.1-.9-2-2-2z"></path>-->
        <!--        </svg>-->
        <!--      </div>-->
        <!--      <div class="label">Bookmarks</div>-->
        <!--    </div>-->
        <!--    <div class="bookmarks-panel-button">New Bookmark</div>-->
        <!--  </div>-->
        <!--  <div class="bookmarks-panel-row"></div>-->
        <!--</div>-->
      </div>
      <div class="Panel SearchPanel" :class="SearchPanelShow?'open':'closed'">
        <!--<div class="Button close-btn hide-in-desktop hide-in-tablet" data-element="searchPanelCloseButton">-->
        <!--  <div class="Icon ">-->
        <!--    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">-->
        <!--      <path d="m0 0h24v24h-24z" fill="none"></path>-->
        <!--      <path-->
        <!--        d="m19 6.41-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"></path>-->
        <!--    </svg>-->
        <!--  </div>-->
        <!--</div>-->
        <div class="results wild-card-visible" v-if="SearchPanelShow">
          <!--<div class="info">没有找到任何结果</div>-->
          <div class="result-page-item" v-for="item in searchResultShowList" :key="item.pageIndex">
            <div class="ListSeparator">第 {{item.pageIndex+1}} 页</div>
            <div class="SearchResult" ref="SearchResult"
                 :class="{selected:listItem.searchResultIndex===searchResultIndex}"
                 v-for="listItem in item.list" v-html="listItem.html"
                 @click="searchResultIndex=listItem.searchResultIndex"
                 :key="listItem.searchResultIndex">
              <!--<span class="search-value">a</span>sdgasdgasdgasdg 阿桑的歌-->
            </div>
          </div>
        </div>
      </div>
      <div class="Overlay SearchOverlay"
           @mousedown.stop @touchstart.stop
           :class="[SearchOverlayShow?'open':'closed',{        transformed:SearchPanelShow      }      ]">
        <div class="wrapper">
          <div class="main">
            <div class="input-wrapper">
              <input type="text" autocomplete="off" v-model="searchText">
            </div>
            <div class="number-of-results">
              <div>{{searchResultIndex+1}} / {{searchResultShowList.reduce((sum, item) => sum + item.list.length, 0)}}
              </div>
            </div>
            <div class="button previous" @click="prevSearchResult()">
              <div class="Icon ">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
                  <path d="m0 0h24v24h-24z" fill="none"></path>
                  <path d="m15.41 7.41-1.41-1.41-6 6 6 6 1.41-1.41-4.58-4.59z"></path>
                </svg>
              </div>
            </div>
            <div class="button next" @click="nextSearchResult()">
              <div class="Icon ">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
                  <path d="m0 0h24v24h-24z" fill="none"></path>
                  <path d="m10 6-1.41 1.41 4.58 4.59-4.58 4.59 1.41 1.41 6-6z"></path>
                </svg>
              </div>
            </div>
            <div class="advanced" @click="SearchPanelShow=true">
              <div class="Icon ">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
                  <path d="m0 0h24v24h-24z" fill="none"></path>
                  <path
                    d="m12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path>
                </svg>
              </div>
            </div>
          </div>
          <!--<div class="options ">-->
          <!--  <div class="search-option"><input class="Input" id="case-sensitive-option" type="checkbox"-->
          <!--                                    label="Case sensitive"><label class="Input" for="case-sensitive-option">Case-->
          <!--    sensitive</label></div>-->
          <!--  <div class="search-option"><input class="Input" id="whole-word-option" type="checkbox"-->
          <!--                                    label="Whole word"><label class="Input" for="whole-word-option">Whole-->
          <!--    word</label></div>-->
          <!--  <div class="search-option" data-element="wildCardSearchOption"><input class="Input" id="wild-card-option"-->
          <!--                                                                        type="checkbox"-->
          <!--                                                                        label="Wildcard"><label class="Input"-->
          <!--                                                                                                for="wild-card-option">Wildcard</label>-->
          <!--  </div>-->
          <!--</div>-->
        </div>
      </div>
      <div class="Overlay PageNavOverlay" :class="[hidePagenav?'closed':'open',{shifted:LeftPanelShow}]">
        <div>
          <input type="text" tabindex="-1"
                 @keydown="handleScaleKeyDown"
                 @keyup="handleScaleKeyUp"
                 @keypress.enter="handlePageIndexEnter"
                 :value="currPageIndex+1" :style="pageIndexInputStyle"> / {{dataList.length}}
        </div>
      </div>
      <div class="Overlay ZoomOverlay" :class="ZoomOverlayShow?'open':'closed'"
           @click="handleZoomOverlayClick"
           @mousedown.stop @touchstart.stop ref="ZoomOverlay">
        <div class="OverlayItem" data-type="page-width">
          <div class="ButtonText">适合页宽</div>
        </div>
        <div class="OverlayItem" data-type="page-fit">
          <div class="ButtonText">适合页面</div>
        </div>
        <div class="spacer"></div>
        <div class="OverlayItem" data-type="0.1" v-show="minScale<=0.1">
          <div class="ButtonText">10%</div>
        </div>
        <div class="OverlayItem" data-type="0.25" v-show="minScale<=0.25">
          <div class="ButtonText">25%</div>
        </div>
        <div class="OverlayItem" data-type="0.5" v-show="minScale<=0.5">
          <div class="ButtonText">50%</div>
        </div>
        <div class="OverlayItem" data-type="1" v-show="minScale<=1&&maxScale>=1">
          <div class="ButtonText">100%</div>
        </div>
        <div class="OverlayItem" data-type="1.25" v-show="maxScale>=1.25">
          <div class="ButtonText">125%</div>
        </div>
        <div class="OverlayItem" data-type="1.5" v-show="maxScale>=1.5">
          <div class="ButtonText">150%</div>
        </div>
        <div class="OverlayItem" data-type="2" v-show="maxScale>=2">
          <div class="ButtonText">200%</div>
        </div>
        <div class="OverlayItem" data-type="4" v-show="maxScale>=4">
          <div class="ButtonText">400%</div>
        </div>
        <!--<div class="spacer"></div>-->
        <!--<div class="Button ToolButton"><p>Marquee Zoom</p></div>-->
      </div>
      <div class="Popup ToolStylePopup" @mousedown.stop @touchstart.stop ref="ToolStylePopup"
           :class="ToolStylePopupShow?'open':'closed'">
        <div class="Popup StylePopup" v-if="currPointerConfig">
          <div class="colors-container">
            <div class="inner-wrapper">
              <div class="stylePopup-title" v-show="currPointerConfig.paletteList.length>1">
                <div class="palette-title">
                  {{currPointerConfig.paletteList[currPointerConfig.paletteIndex].label}}颜色
                </div>
                <div class="palette">
                  <div :class="['palette-item',item.key,{selected:currPointerConfig.paletteIndex===idx}]"
                       @click="currPointerConfig.paletteIndex=idx"
                       v-for="(item,idx) in currPointerConfig.paletteList" :key="idx">
                    <div v-if="item.key==='text'" :style="{color:currPointerConfig.text}">Aa</div>
                    <div v-else-if="item.key==='fill'" :style="{backgroundColor:currPointerConfig.fill}">
                      <div v-if="currPointerConfig.fill==='transparent'"></div>
                    </div>
                    <div v-else :style="{borderColor:currPointerConfig.stroke}">
                      <div v-if="currPointerConfig.stroke==='transparent'"></div>
                    </div>
                  </div>
                </div>
              </div>
              <div class="ColorPalette">
                <div class="cell"
                     @click="setPointerConfig(pointerType,currPointerConfig.paletteList[currPointerConfig.paletteIndex].key,color)"
                     :style="{'background-color': color,border:color==='rgb(255, 255, 255)'?'1px solid rgb(224, 224, 224)':''}"
                     :key="idx"
                     v-for="(color,idx) in colorList">
                  <div class="Icon check-mark bright"
                       v-if="currPointerConfig[currPointerConfig.paletteList[currPointerConfig.paletteIndex].key]===color">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
                      <path d="m0 0h24v24h-24z" fill="none"></path>
                      <path d="m9 16.17-4.17-4.17-1.42 1.41 5.59 5.59 12-12-1.41-1.41z"></path>
                    </svg>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="sliders-container">
            <div class="sliders">
              <div class="slider-item" v-for="(item,idx) in currPointerConfig.sliderList" :key="idx">
                <div class="slider__property">{{item.label}}</div>
                <Slider :max="item.max" :min="item.min" :step="item.step"
                        @input="setPointerConfig(pointerType,item.key,$event)" :value="currPointerConfig[item.key]"/>
                <div class="slider__value">{{currPointerConfig[item.key]}}</div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="Modal LoadingModal closed">
        <div class="container">
          <div class="inner-wrapper"></div>
        </div>
      </div>
      <div class="Modal ProgressModal" :class="progressOpen?'open':'closed'">
        <div class="container">
          <div class="progress-bar-wrapper">
            <div class="progress-bar" :style="{transform: `translateX(-${100-loadedProgress}%)`}"></div>
          </div>
        </div>
      </div>
      <div class="debugger-info" v-if="isDebugg">
        <div class="debugger-info__item">视图大小：{{viewSize}}</div>
        <div class="debugger-info__item">滚动高度：{{scrollHeight}}</div>
        <div class="debugger-info__item">当前滚动高度：{{scrollTop}}</div>
        <div class="debugger-info__item">当前滚动宽度：{{scrollLeft}}</div>
        <div class="debugger-info__item">据顶部距离：{{deltaTop}}</div>
      </div>
    </div>
  </div>
</template>

<script>
  // import 'handjs'
  import vueResizeSensor from 'vue-resize-sensor'
  import {copyText, decodeBase64, openMask, uuid} from "../util/util";
  import Button from "@/components/Marking/src/Button";
  import pageContainer from "@/components/Marking/src/pageContainer/pageContainer";
  import {addEventListener, removeEventListener} from '../util/eventManager'
  import getTextWidth from "@/util/getTextWidth";
  import Slider from "@/components/Marking/src/Slider";
  import moment from 'moment'
  import VueKonva from "@/components/vue-konva";

  const {vStage, vLayer, vImage} = VueKonva

  const errorImgSrc = require('@/assets/img/errorImg.jpg')

  const isDev = process.env.NODE_ENV !== 'production'

  export default {
    components: {
      vueResizeSensor, Button, pageContainer, Slider, vStage, vLayer, vImage
    },
    props: {
      selectionBgColor: {
        type: String,
        default: 'rgba(0,180,255,0.5)'
      },
      dataLoadFn: Function,
      hidePagenav: {
        type: Boolean,
        default: false
      },
      hideToolbox: {
        type: Boolean,
        default: false
      },
      hideContextmenupopup: {
        type: Boolean,
        default: false
      },
      maxScale: {
        type: Number,
        default: 4
      },
      threshold: {
        type: Number,
        default: 100
      },
      textpopupDisableelement: {
        type: Array,
        default: () => []
      },
      contextmenupopupDisableelement: {
        type: Array,
        default: () => []
      }
    },
    data() {
      return {
        isDebugg: isDev,
        displayMode: 'continuous',// continuous 连续 single 逐页
        LeftPanelTabType: 'thumbnails', // thumbnails annotations
        annotationShowList: [],
        annotationList: [],
        selectionList: [],
        isOnText: false,
        isOnShape: false,
        isGrabbing: false,
        searchText: '',
        searchResultList: [],
        searchResultShowList: [],
        searchResultIndex: -1,
        evManager: {},
        maxImageWidth: 0,
        minImageHeight: 0,
        maxImageHeight: 0,
        viewSize: {
          width: 0,
          height: 0
        },
        dataList: [],
        scrollHeight: 0,
        scrollTop: -1,
        scrollLeft: 0,
        loadedProgress: 0,
        progressOpen: false,
        privateData: {
          scaleType: 'page-fit'
        },
        TextPopupShow: false,
        ContextMenuPopupShow: false,
        TextPopupButtonList: [
          {
            component: Button,
            props: {name: 'copy'},
            click: () => {
              this.copySelectText()
            }
          }, {
            component: Button,
            props: {name: 'highlight'},
            click: () => {
              this.selectionListToAnnotation()
            }
          }],
        ContextMenuPopupButtonList: [
          {
            component: Button,
            props: {name: 'pan'},
            click: () => {
              this.setPointerType('hand')
            }
          }, {
            component: Button,
            props: {name: 'highlight'},
            click: () => {
              // this.setPointerType('hand')
            }
          }, {
            component: Button,
            props: {name: 'freeLine'},
            click: () => {
              this.setPointerType('freeLine')
            }
          }, {
            component: Button,
            props: {name: 'freeText'},
            click: () => {
              this.setPointerType('freeText')
            }
          }],
        ZoomOverlayShow: false,
        SearchOverlayShow: false,
        SearchPanelShow: false,
        LeftPanelShow: false,
        ToolStylePopupShow: false,
        showPageIndex: 0,
        pageCount: 5,
        pointerType: 'select',
        colorList: [
          'rgb(241, 160, 153)',
          'rgb(255, 198, 123)',
          'rgb(255, 230, 162)',
          'rgb(128, 229, 177)',
          'rgb(146, 232, 232)',
          'rgb(166, 161, 230)',
          'rgb(226, 161, 230)',
          'rgb(228, 66, 52)',
          'rgb(255, 141, 0)',
          'rgb(255, 205, 69)',
          'rgb(0, 204, 99)',
          'rgb(37, 210, 209)',
          'rgb(78, 125, 233)',
          'rgb(197, 68, 206)',
          'rgb(136, 39, 31)',
          'rgb(181, 72, 0)',
          'rgb(246, 154, 0)',
          'rgb(0, 122, 59)',
          'rgb(22, 126, 125)',
          'rgb(46, 75, 139)',
          'rgb(118, 40, 123)',
          'transparent',
          'rgb(255, 255, 255)',
          'rgb(205, 205, 205)',
          'rgb(156, 156, 156)',
          'rgb(105, 105, 105)',
          'rgb(55, 55, 55)',
          'rgb(0, 0, 0)'
        ],
        pointerConfig: {
          highlight: {
            paletteIndex: 0,
            paletteList: [{key: 'fill', label: '填充'}],
            sliderList: [{key: 'opacity', label: '透明度', min: 0, max: 1, step: 0.01}],
            fill: 'rgb(0, 0, 0)',
            strokeWidth: 1,
            stroke: 'transparent',
            opacity: 0.3,
          },
          rect: {
            paletteIndex: 0,
            paletteList: [{key: 'stroke', label: '边框'}, {key: 'fill', label: '填充'}],
            sliderList: [{key: 'opacity', label: '透明度', min: 0, max: 1, step: 0.01},
              {key: 'strokeWidth', label: '边框粗细', min: 1, max: 20, step: 1}],
            fill: 'transparent',
            strokeWidth: 1,
            stroke: 'rgb(0, 0, 0)',
            opacity: 1,
          },
          ellipse: {
            paletteIndex: 0,
            paletteList: [{key: 'stroke', label: '边框'}, {key: 'fill', label: '填充'}],
            sliderList: [{key: 'opacity', label: '透明度', min: 0, max: 1, step: 0.01},
              {key: 'strokeWidth', label: '边框粗细', min: 1, max: 20, step: 1}],
            fill: 'transparent',
            strokeWidth: 1,
            stroke: 'rgb(0, 0, 0)',
            opacity: 1
          },
          line: {
            paletteIndex: 0,
            paletteList: [{key: 'stroke', label: '边框'}],
            sliderList: [{key: 'opacity', label: '透明度', min: 0, max: 1, step: 0.01},
              {key: 'strokeWidth', label: '边框粗细', min: 1, max: 20, step: 1}],
            strokeWidth: 1,
            stroke: 'rgb(228, 66, 52)',
            opacity: 1
          },
          freeLine: {
            paletteIndex: 0,
            paletteList: [{key: 'stroke', label: '边框'}],
            sliderList: [{key: 'opacity', label: '透明度', min: 0, max: 1, step: 0.01},
              {key: 'strokeWidth', label: '边框粗细', min: 1, max: 20, step: 1}],
            strokeWidth: 1,
            stroke: 'rgb(228, 66, 52)',
            opacity: 1
          },
          arrow: {
            paletteIndex: 0,
            paletteList: [{key: 'stroke', label: '边框'}],
            sliderList: [{key: 'opacity', label: '透明度', min: 0, max: 1, step: 0.01},
              {key: 'strokeWidth', label: '边框粗细', min: 1, max: 20, step: 1}],
            strokeWidth: 1,
            stroke: 'rgb(228, 66, 52)',
            opacity: 1
          },
          freeText: {
            paletteIndex: 0,
            paletteList: [{key: 'text', label: '文字'},
              {key: 'stroke', label: '边框'},
              {key: 'fill', label: '填充'}],
            sliderList: [{key: 'opacity', label: '透明度', min: 0, max: 1, step: 0.01},
              {key: 'strokeWidth', label: '边框粗细', min: 1, max: 20, step: 1},
              {key: 'fontSize', label: '文字大小', min: 5, max: 45, step: 1}],
            fontSize: 10,
            strokeWidth: 1,
            stroke: 'transparent',
            text: 'rgb(228, 66, 52)',
            fill: 'transparent',
            opacity: 1
          }
        },
      }
    },
    computed: {
      dataShowList() {
        if (this.displayMode === 'continuous') {
          return this.dataList
        } else if (this.displayMode === 'single') {
          let dataItem = this.dataList.find(item => item.pageIndex === this.currPageIndex)
          return dataItem ? [dataItem] : []
        }
      },
      currPageIndex: {
        get() {
          if (this.displayMode === 'single') return this.showPageIndex
          // if (!this.scrollTop < 0) return -1
          let p = (this.scrollTop + this.viewSize.height / 2) / (this.scrollHeight + this.viewSize.height)
          let currPageIndex = Math.floor(p * this.dataList.length) || 0
          return currPageIndex
        },
        set(val) {
          this.showPageIndex = val
        }
      },
      // searchResultShowList() {
      //   let res = []
      //   let searchRe = new RegExp(this.searchText)
      //   this.searchResultList.map(item => {
      //     let resItem = res.find(__item => __item.pageIndex === item.pageIndex)
      //     if (!resItem) {
      //       resItem = {
      //         pageIndex: item.pageIndex,
      //         list: [{
      //           text: item.text,
      //           html: item.text.replace(searchRe, w => `<span class="search-value">${w}</span>`),
      //           searchResultIndex: item.searchResultIndex
      //         }]
      //       }
      //       res.push(resItem)
      //     } else {
      //       resItem.list.push({
      //         text: item.text,
      //         html: item.text.replace(searchRe, w => `<span class="search-value">${w}</span>`),
      //         searchResultIndex: item.searchResultIndex
      //       })
      //     }
      //   })
      //   return res
      // },
      currPointerConfig() {
        return this.pointerConfig[this.pointerType]
      },
      DocumentContainerStyle() {
        let cursor = 'default'
        switch (this.pointerType) {
          case "line":
          case "freeLine":
          case "ellipse":
          case "rect":
          case "arrow":
          case "eraser":
            cursor = 'crosshair'
            break
          case "highlight":
          case "select":
            if (this.isOnText) cursor = 'text'
            if (this.isOnShape) cursor = 'pointer'
            break
          case "hand":
            cursor = 'grab'
            if (this.isGrabbing) cursor = 'grabbing'
            break
        }
        // console.log(this.isOnText, cursor)
        return {
          touchAction: this.pointerType === 'hand' ? 'auto' : 'none',
          cursor: cursor
        }
      },
      pageIndexInputStyle() {
        let width = getTextWidth(`${this.dataList.length}`, '16px')
        return {
          width: width + 'px'
        }
      },
      deltaTop() {
        if (this.scrollHeight > 0) return 0
        else return (this.viewSize.height - this.dataList.reduce((sum, item) => (sum + item.imgSize.height * this.scale), 0)) / 2
      },
      minScale() {
        return this.viewSize.height / (this.minImageHeight * this.pageCount)
      },
      scale() {
        if (!this.maxImageWidth || !this.maxImageHeight) return 1
        if (this.displayMode === 'single') return Math.min(this.viewSize.width / this.maxImageWidth, this.viewSize.height / this.maxImageHeight)
        if (typeof this.scaleType === 'number') return this.scaleType
        if (this.scaleType === 'page-width') return this.viewSize.width / this.maxImageWidth
        return Math.min(this.viewSize.width / this.maxImageWidth, this.viewSize.height / this.maxImageHeight)
      },
      scaleType: {
        get() {
          return this.privateData.scaleType
        },
        set(val) {
          if (typeof val === 'number') {
            if (val < this.minScale) val = this.minScale
            else if (val > this.maxScale) val = this.maxScale
          }
          this.privateData.scaleType = val
        }
      }
    },
    watch: {
      currPageIndex(newVal, oldVal) {
        this.sendEvent('page-change', this.currPageIndex)

        this.$nextTick(() => {
          let Thumbnails = this.$refs.Thumbnail
          if (!Thumbnails) return
          let Thumbnail = Thumbnails[newVal]
          if (Thumbnail) Thumbnail.scrollIntoView({block: "nearest"})
        })
      },
      scrollTop() {
        this.$nextTick(() => {
          let DocumentContainer = this.$refs.DocumentContainer
          this.scrollHeight = DocumentContainer.scrollHeight - DocumentContainer.clientHeight
          // this.currPageIndex = this.getPageIndexByViewPos({
          //   x: this.viewSize.width / 2,
          //   y: this.viewSize.height / 2,
          // })
          // this.viewSize = {
          //   width: DocumentContainer.clientWidth,
          //   height: DocumentContainer.clientHeight
          // }
        })
      },
      searchText(val) {
        this.search(val)
      },
      searchResultIndex(val) {
        this.$nextTick(() => {
          let SearchResults = this.$refs.SearchResult
          if (SearchResults && SearchResults[val]) {
            SearchResults[val].scrollIntoView({block: "nearest"})
          }

          this.$nextTick(() => {
            let showItem = this.searchResultShowList.find(item => item.list.some(_item => _item.searchResultIndex === val))
            if (!showItem) return
            let resInfo = showItem.list.find(_item => _item.searchResultIndex === val)
            let pageIndex = showItem.pageIndex
            let scrollTop = 0
            for (let i = 0; i < pageIndex; i++) {
              let imgSize = this.dataList[i].imgSize
              scrollTop += (imgSize.height * this.scale + 8 * this.scale)
            }
            let h = (resInfo.startWord.y2 + resInfo.startWord.y1) / 2 * this.scale
            let deltaH = this.viewSize.height / 2 - h
            this.scrollTo({y: scrollTop - deltaH})
          })
        })
      },
      TextPopupShow(val) {
        if (val) {
          this.evManager['TextPopupShow-mousedown'] = e => {
            // let el = e.target
            // do {
            //   if (el.classList.contains('toggleLeftButton')) return
            // } while ((el = el.parentElement))
            this.TextPopupShow = false
          }
          addEventListener('mousedown', this.evManager['TextPopupShow-mousedown'])
        } else {
          removeEventListener('mousedown', this.evManager['TextPopupShow-mousedown'])
        }
      },
      ContextMenuPopupShow(val) {
        if (val) {
          this.evManager['ContextMenuPopupShow-mousedown'] = e => {
            // let el = e.target
            // do {
            //   if (el.classList.contains('toggleLeftButton')) return
            // } while ((el = el.parentElement))
            this.ContextMenuPopupShow = false
          }
          addEventListener('mousedown', this.evManager['ContextMenuPopupShow-mousedown'])
        } else {
          removeEventListener('mousedown', this.evManager['ContextMenuPopupShow-mousedown'])
        }
      },
      ToolStylePopupShow(val) {
        if (val) {
          this.evManager['ToolStylePopupShow-mousedown'] = e => {
            let el = e.target
            do {
              if (el.classList.contains('ToolButton')) return
            } while ((el = el.parentElement))
            this.ToolStylePopupShow = false
          }
          addEventListener('mousedown', this.evManager['ToolStylePopupShow-mousedown'])
        } else {
          removeEventListener('mousedown', this.evManager['ToolStylePopupShow-mousedown'])
        }
      },
      ZoomOverlayShow(val) {
        if (val) {
          this.evManager['ZoomOverlayShow-mousedown'] = e => {
            let el = e.target
            do {
              if (el.classList.contains('zoomOverlayButton')) return
            } while ((el = el.parentElement))
            this.ZoomOverlayShow = false
          }
          console.log('绑定事件')
          addEventListener('mousedown', this.evManager['ZoomOverlayShow-mousedown'])
        } else {
          console.log('解绑事件')
          removeEventListener('mousedown', this.evManager['ZoomOverlayShow-mousedown'])
        }
      },
      SearchOverlayShow(val) {
        if (val) {
          this.evManager['SearchOverlayShow-mousedown'] = e => {
            let el = e.target
            do {
              if (el.classList.contains('SearchOverlayButton')) return
            } while ((el = el.parentElement))
            if (this.SearchPanelShow) return;
            this.SearchOverlayShow = false
          }
          console.log('绑定事件')
          addEventListener('mousedown', this.evManager['SearchOverlayShow-mousedown'])
        } else {
          this.SearchPanelShow = false
          this.searchText = ''
          console.log('解绑事件')
          removeEventListener('mousedown', this.evManager['ZoomOverlayShow-mousedown'])
        }
      },
    },
    mounted() {
      // window.addEventListener('pointerdown', e => {
      //   console.log('pointerdown', e.pointerType)
      //   let oldPointerType = ''
      //   if (this.pointerType === 'hand' || this.pointerType === 'select') {
      //     oldPointerType = this.pointerType
      //     if (e.pointerType === 'touch') {
      //       this.pointerType = 'hand'
      //     } else {
      //       this.pointerType = 'select'
      //     }
      //   }
      //   let up = e => {
      //     if (oldPointerType) this.pointerType = oldPointerType
      //     window.removeEventListener("pointerup", up)
      //   }
      //   window.addEventListener("pointerup", up)
      // })
      let pointerConfig = JSON.parse(localStorage.getItem('pointerConfig')) || {}

      for (const pointerType in pointerConfig) {
        for (const field in pointerConfig[pointerType]) {
          this.setPointerConfig(pointerType, field, pointerConfig[pointerType][field])
        }
      }
    },
    methods: {
      test() {
        let move = e => {
          console.log(this.getPointerPosOnView())
        }
        openMask(move)
      },
      setPointerConfig(pointerType, field, value) {
        this.pointerConfig[pointerType][field] = value
        let pointerConfig = JSON.parse(localStorage.getItem('pointerConfig')) || {}
        if (!pointerConfig[pointerType]) pointerConfig[pointerType] = {}
        pointerConfig[pointerType][field] = value
        localStorage.setItem('pointerConfig', JSON.stringify(pointerConfig))
      },
      search(searchText) {
        this.searchText = searchText
        this.searchResultList = []
        this.searchResultShowList = []
        this.searchResultIndex = -1

        if (!this.searchText) return
        let textarr = this.searchText.split('')
        for (let i = 0; i < this.dataList.length; i++) {
          let dataItem = this.dataList[i]
          let words = dataItem.words
          if (!words || !words.length) continue
          let prevIndex = 0
          for (let j = 0; j < words.length - textarr.length; j++) {
            let ok = textarr.every((txt, k) => words[j + k].text === txt)
            if (ok) {
              let start = words[j]
              let end = words[j + textarr.length - 1]
              let beforeText = ''
              let afterText = ''
              for (let k = j - 1; k > 0; k--) {
                if (k <= prevIndex) break
                if (/[.。!！?？]/.test(words[k].text)) break
                beforeText = words[k].text + beforeText
              }
              for (let k = j + textarr.length; k < words.length; k++) {
                afterText += words[k].text
                if (/[.。!！?？]/.test(words[k].text)) break
              }
              prevIndex = j + textarr.length - 1
              this.addSearchResult({
                pageIndex: i, start, end,
                text: `${beforeText}${searchText}${afterText}`
              })
              j += (textarr.length - 1)
            }
          }
        }
      },
      addSearchResult(searchResult) {
        if (this.searchResultIndex === -1) this.searchResultIndex = 0

        let len = this.searchResultShowList.reduce((sum, item) => sum + item.list.length, 0)
        // let A = this.getWordByWordPos(searchResult.start)
        // let B = this.getWordByWordPos(searchResult.end)
        let rectList = this.getRectListByAToB(searchResult.start, searchResult.end)
        rectList.forEach(item => {
          item.className = 'rect'
          item.relationId = 'search-result-' + len
          item.type = 'search-result'
          item.searchResultIndex = len
          item.id = `search-result-${item.id}`
          item.attrs = {...item.attrs, fill: 'rgba(255,252,149,0.3)'}
        })
        // console.log(rectList)
        // let ids = rectList.map(item => item.id)
        // this.clearSelection(ids)
        // rectList.map(item => {
        // this.addAnnotation(...rectList)
        searchResult.searchResultIndex = len
        this.searchResultList.push(...rectList)

        let searchRe = new RegExp(this.searchText)
        let resItem = this.searchResultShowList.find(__item => __item.pageIndex === searchResult.pageIndex)
        if (!resItem) {
          resItem = {
            pageIndex: searchResult.pageIndex,
            list: [{
              startWord: searchResult.start,
              text: searchResult.text,
              html: searchResult.text.replace(searchRe, w => `<span class="search-value">${w}</span>`),
              searchResultIndex: searchResult.searchResultIndex
            }]
          }
          this.searchResultShowList.push(resItem)
        } else {
          resItem.list.push({
            startWord: searchResult.start,
            text: searchResult.text,
            html: searchResult.text.replace(searchRe, w => `<span class="search-value">${w}</span>`),
            searchResultIndex: searchResult.searchResultIndex
          })
        }
      },
      prevSearchResult() {
        let len = this.searchResultShowList.reduce((sum, item) => sum + item.list.length, 0)
        if (!len) return this.searchResultIndex = -1
        if (this.searchResultIndex === 0) return this.searchResultIndex = len - 1
        this.searchResultIndex--
      },
      nextSearchResult() {
        let len = this.searchResultShowList.reduce((sum, item) => sum + item.list.length, 0)
        if (!len) return this.searchResultIndex = -1
        if (this.searchResultIndex === len - 1) return this.searchResultIndex = 0
        this.searchResultIndex++
      },
      sendEvent() {
        this.$emit(...arguments)
      },
      handleButtonClick(ev, pointerType) {
        if (this.pointerType !== pointerType) {
          this.ToolStylePopupShow = false
          this.setPointerType(pointerType)
          return
        }
        if (this.ToolStylePopupShow) return this.ToolStylePopupShow = false
        let target = ev.target
        const pos = this.getPosByPdfMarkingContent(target)
        let deltaW = 256 - target.offsetWidth
        let scrollLeft = target.parentElement.scrollLeft
        let x = pos.x - (deltaW) / 2 - scrollLeft
        let y = pos.y + target.offsetHeight
        let width = this.$refs.pdfMarkingContent.offsetWidth
        if (x + 256 > width) x = width - 256
        this.$refs.ToolStylePopup.style.left = x + 'px'
        this.$refs.ToolStylePopup.style.top = y + 'px'
        this.ToolStylePopupShow = true
        // console.log('handleButtonClick', this.$refs.ToolStylePopup)
      },
      setPointerType(pointerType) {
        this.pointerType = pointerType
      },
      removeAnnotationById(id) {
        for (let i = 0; i < this.annotationList.length; i++) {
          let item = this.annotationList[i]
          if (item.id === id) {
            this.removeAnnotationShow(item)
            this.annotationList.splice(i, 1)
            i--
          }
        }
      },
      removeAnnotationByType(type) {
        for (let i = 0; i < this.annotationList.length; i++) {
          let item = this.annotationList[i]
          if (item.type === type) {
            this.removeAnnotationShow(item)
            this.annotationList.splice(i, 1)
            i--
          }
        }
      },
      removeAnnotation(relationId) {
        for (let i = 0; i < this.annotationList.length; i++) {
          let item = this.annotationList[i]
          if (item.relationId === relationId) {
            this.removeAnnotationShow(item)
            this.annotationList.splice(i, 1)
            i--
          }
        }
      },
      selectionListToAnnotation() {
        let pages = {}
        let relations = {}
        this.selectionList.sort((a, b) => {
          if (a.pageIndex !== b.pageIndex) return a.pageIndex - b.pageIndex
          return a.startIndex - b.startIndex
        })
        for (let i = 0; i < this.selectionList.length; i++) {
          let selectionItem = this.selectionList[i]
          if (!pages[selectionItem.pageIndex]) pages[selectionItem.pageIndex] = []
          pages[selectionItem.pageIndex].push(selectionItem)
        }
        for (const pageIndex in pages) {
          let list = pages[pageIndex]
          let start = `${pageIndex}-${list[0].startIndex}`
          let end = `${pageIndex}-${list[list.length - 1].endIndex}`
          let startWord = this.getWordByWordPos(start)
          let endWord = this.getWordByWordPos(end)
          let rectList = this.getRectListByAToB(startWord, endWord)
          let relationId = uuid()
          let c = this.pointerConfig['highlight']
          rectList.forEach(item => {
            item.pointerType = 'highlight'
            item.createTime = moment().format('YYYY-MM-DD HH:mm:ss')
            item.relationId = relationId
            item.id = `${relationId}-${item.id}`
            item.attrs.fill = c.fill
            item.attrs.opacity = c.opacity
            delete item.startIndex
            delete item.endIndex
          })
          this.addAnnotationNotOverflow(...rectList)
          relations[relationId] = rectList
        }
        this.sendEvent('annotation-change', relations, 'add')
        this.clearSelection()
      },
      handleAnnotationListDeleteBtnClick(relationId) {
        let annos = this.annotationList.filter(item => item.relationId === relationId)
        this.sendEvent('annotation-change', {
          [relationId]: annos
        }, 'delete')
        this.removeAnnotation(relationId)
      },
      addAnnotation(...annotations) {
        // this.annotationList.push(...annotations)
        for (let i = 0; i < annotations.length; i++) {
          let annotation = annotations[i]
          let index = this.annotationList.findIndex(item => item.relationId === annotation.relationId)
          if (index > -1) {
            this.annotationList.splice(index, 1, annotation)
          } else this.annotationList.push(annotation)
          this.addAnnotationShow(annotation)
        }
      },
      addAnnotationNotOverflow(...annotations) {
        this.annotationList.push(...annotations)
        let groupByRelationId = {}
        for (let i = 0; i < annotations.length; i++) {
          let _annotation = annotations[i]
          if (!groupByRelationId[_annotation.relationId]) groupByRelationId[_annotation.relationId] = []
          groupByRelationId[_annotation.relationId].push(_annotation)
        }
        for (const relationId in groupByRelationId) {
          let list = groupByRelationId[relationId]
          let text = list.map(item => item.text).join('\n')
          let annotation = {
            pageIndex: list[0].pageIndex,
            relationId: relationId,
            pointerType: list[0].pointerType,
            attrs: {},
            createTime: list[0].createTime,
            text: text
          }
          if (/highlight/.test(annotation.pointerType)) {
            annotation.attrs.fill = list[0].attrs.fill
          } else {
            annotation.attrs.stroke = list[0].attrs.stroke
          }
          this.addAnnotationShow(annotation)
        }
      },
      addAnnotationShow(annotation) {
        let pageItem = this.annotationShowList.find(_item => _item.pageIndex === annotation.pageIndex)
        if (!pageItem) {
          pageItem = {pageIndex: annotation.pageIndex, list: []}
          this.annotationShowList.push(pageItem)
        }
        let idx = pageItem.list.findIndex(_item => _item.relationId === annotation.relationId)
        let item = {
          relationId: annotation.relationId,
          pointerType: annotation.pointerType,
          color: annotation.attrs.stroke || annotation.attrs.fill,
          createTime: annotation.createTime,
          text: annotation.text
        }
        if (idx < 0) {
          pageItem.list.push(item)
        } else {
          pageItem.list.splice(idx, 1, item)
        }
        this.annotationShowList.sort((a, b) => a.pageIndex - b.pageIndex)
      },
      removeAnnotationShow(annotation) {
        let index = this.annotationShowList.findIndex(_item => _item.pageIndex === annotation.pageIndex)
        let pageItem = this.annotationShowList[index]
        if (!pageItem) return
        let idx = pageItem.list.findIndex(_item => _item.relationId === annotation.relationId)
        if (idx < 0) return;
        pageItem.list.splice(idx, 1)
        if (!pageItem.list.length) this.annotationShowList.splice(index, 1)
      },
      addSelection(...selections) {
        for (let i = 0; i < selections.length; i++) {
          let selection = selections[i]
          let index = this.selectionList.findIndex(item => item.id === selection.id)
          if (index > -1) {
            this.selectionList.splice(index, 1, selection)
          } else this.selectionList.push(selection)
        }
      },
      clearSelection(ids = []) {
        for (let i = 0; i < this.selectionList.length; i++) {
          let item = this.selectionList[i]
          if (ids.indexOf(item.id) === -1) {
            this.selectionList.splice(i, 1)
            i--
          }
        }
      },
      copySelectText() {
        let selectionList = JSON.parse(JSON.stringify(this.selectionList))
        let re = /selection-rect-(\d+)_(\d+)/
        selectionList.sort((a, b) => {
          let aIndex = 0
          let bIndex = 0
          if (re.test(a.id)) {
            let pageIndex = RegExp.$1
            let rowIndex = RegExp.$2
            for (let i = rowIndex.length; i < 5; i++) rowIndex = '0' + rowIndex
            aIndex = Number(pageIndex + rowIndex)
          }
          if (re.test(b.id)) {
            let pageIndex = RegExp.$1
            let rowIndex = RegExp.$2
            for (let i = rowIndex.length; i < 5; i++) rowIndex = '0' + rowIndex
            bIndex = Number(pageIndex + rowIndex)
          }
          return aIndex - bIndex
        })
        let text = selectionList.map(item => item.text).join('\n')
        copyText(text)
      },
      handleTextPopupButtonClick(ev, item) {
        this.TextPopupShow = false
        if (item.click) {
          item.click(ev)
        }
      },
      handleContextMenuPopupButtonClick(ev, item) {
        this.ContextMenuPopupShow = false
        if (item.click) {
          item.click(ev)
        }
      },
      addAnnotationData(arg, type = '') {
        let hasStart = arg.hasOwnProperty('start')
        let hasEnd = arg.hasOwnProperty('end')

        let className = arg.className || 'rect'
        let relationId = arg.id || uuid()

        if (hasStart && hasEnd) {
          // 文本标记
          let A = this.getWordByWordPos(arg.start)
          let B = this.getWordByWordPos(arg.end)
          let rectList = this.getRectListByAToB(A, B)
          rectList.forEach(item => {
            item.className = className
            item.relationId = relationId
            item.type = type
            item.id = `${relationId}-${item.id}`
            item.attrs = {...item.attrs, ...arg.attrs}
          })
          // let ids = rectList.map(item => item.id)
          // this.clearSelection(ids)
          // rectList.map(item => {
          this.addAnnotation(...rectList)
          // })
        } else {
          // 其余标记
          let annotation = {
            pageIndex: arg.pageIndex,
            className: className,
            relationId: relationId,
            type: type,
            id: `${relationId}-${uuid()}`,
            attrs: {...arg.attrs}
          }
          this.addAnnotation(annotation)
        }
      },
      handleEraser() {
        let relations = {}
        let viewPos = this.getPointerPosOnView()
        let pageIndex = this.getPageIndexByViewPos(viewPos)
        let pageContainer = this.$refs.pageContainer[pageIndex]
        if (!pageContainer) return
        let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
        let shape = pageContainer.getIntersection(imgPos)

        let move = e => {
          let viewPos = this.getPointerPosOnView()
          let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
          let shape = pageContainer.getIntersection(imgPos)
          if (!shape) return
          // console.log(shape)
          let relationId = shape.getAttr('relationId')
          relations[relationId] = JSON.parse(JSON.stringify(this.annotationList.find(item => item.relationId === relationId)))
          this.removeAnnotation(relationId)
        }
        let up = e => {
          delete relations['selection-rect']
          if (Object.keys(relations).length) this.sendEvent('annotation-change', relations, 'delete')
        }
        openMask(move, up)
      },
      handleDrawFreeText() {
        let pageIndex = this.getPageIndexByPointerPos()
        let startImgPos = this.getPointerPosOnImage()
        let id = uuid()

        let c = this.pointerConfig[this.pointerType]

        let annotation = {
          pageIndex,
          id,
          relationId: id,
          className: 'text',
          pointerType: this.pointerType,
          createTime: moment().format('YYYY-MM-DD HH:mm:ss'),
          attrs: {
            x: Math.round(startImgPos.x),
            y: Math.round(startImgPos.y),
            width: 1,
            height: 1,
            fontSize: c.fontSize,
            strokeWidth: c.strokeWidth,
            opacity: c.opacity,
            fill: c.text,
            bgStroke: c.stroke,
            bgColor: c.fill,
            text: '我们通常会在最新版的 Node.js 发布后一个月左右将 Electron 更新到这个版本的 Node.js。 我们通过这种方式来避免新版本的 Node.js 带来的 bug（这种 bug 太常见了）。Node.js 的新特性通常是由新版本的 V8 带来的。由于 Electron 使用的是 Chrome 浏览器中附带的 V8 引擎，所以 Electron 内往往已经有了部分新版本 Node.js 才有的崭新特性'
          }
        }
        const move = e => {
          let viewPos = this.getPointerPosOnView()
          let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
          let x = Math.min(imgPos.x, startImgPos.x)
          let y = Math.min(imgPos.y, startImgPos.y)
          annotation.attrs.width = Math.abs(imgPos.x - startImgPos.x) || 1
          annotation.attrs.height = Math.abs(imgPos.y - startImgPos.y) || 1
          annotation.attrs.x = x
          annotation.attrs.y = y
          this.addAnnotation(annotation)
        }
        const up = e => {
          this.sendEvent('annotation-change', {[id]: [annotation]}, 'add')
        }
        openMask(move, up)
      },
      handleDrawArrow() {
        let pageIndex = this.getPageIndexByPointerPos()
        let startImgPos = this.getPointerPosOnImage()
        let id = uuid()

        let c = this.pointerConfig[this.pointerType]
        let annotation = {
          pageIndex,
          relationId: id,
          pointerType: this.pointerType,
          className: 'arrow',
          createTime: moment().format('YYYY-MM-DD HH:mm:ss'),
          id,
          attrs: {
            points: [Math.round(startImgPos.x), Math.round(startImgPos.y)],
            pointerWidth: 15,
            pointerLength: 25,
            fill: c.fill,
            stroke: c.stroke,
            strokeWidth: c.strokeWidth,
            opacity: c.opacity
          }
        }
        const move = e => {
          let viewPos = this.getPointerPosOnView()
          let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
          let p = [Math.round(startImgPos.x), Math.round(startImgPos.y)].concat(Math.round(imgPos.x), Math.round(imgPos.y))
          this.$set(annotation.attrs, 'points', p)
          this.addAnnotation(annotation)
        }
        const up = e => {
          this.sendEvent('annotation-change', {[id]: [annotation]}, 'add')
        }
        openMask(move, up)
      },
      handleDrawRect() {
        let pageIndex = this.getPageIndexByPointerPos()
        let startImgPos = this.getPointerPosOnImage()
        let id = uuid()

        let c = this.pointerConfig[this.pointerType]

        let annotation = {
          pageIndex,
          id,
          relationId: id,
          className: 'rect',
          pointerType: this.pointerType,
          createTime: moment().format('YYYY-MM-DD HH:mm:ss'),
          attrs: {
            x: Math.round(startImgPos.x),
            y: Math.round(startImgPos.y),
            width: 1,
            height: 1,
            stroke: c.stroke,
            strokeWidth: c.strokeWidth,
            opacity: c.opacity,
            fill: c.fill
          }
        }
        const move = e => {
          let viewPos = this.getPointerPosOnView()
          let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
          let x = Math.min(imgPos.x, startImgPos.x)
          let y = Math.min(imgPos.y, startImgPos.y)
          annotation.attrs.width = Math.abs(imgPos.x - startImgPos.x) || 1
          annotation.attrs.height = Math.abs(imgPos.y - startImgPos.y) || 1
          annotation.attrs.x = x
          annotation.attrs.y = y
          this.addAnnotation(annotation)
        }
        const up = e => {
          this.sendEvent('annotation-change', {[id]: [annotation]}, 'add')
        }
        openMask(move, up)
      },
      handleDrawEllipse() {
        let pageIndex = this.getPageIndexByPointerPos()
        let startImgPos = this.getPointerPosOnImage()
        let id = uuid()
        let c = this.pointerConfig[this.pointerType]
        let annotation = {
          pageIndex,
          id,
          relationId: id,
          className: 'ellipse',
          pointerType: this.pointerType,
          createTime: moment().format('YYYY-MM-DD HH:mm:ss'),
          attrs: {
            x: Math.round(startImgPos.x),
            y: Math.round(startImgPos.y),
            width: 1,
            height: 1,
            fill: c.fill,
            stroke: c.stroke,
            strokeWidth: c.strokeWidth,
            opacity: c.opacity
          }
        }
        const move = e => {
          let viewPos = this.getPointerPosOnView()
          let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
          let x = Math.min(imgPos.x, startImgPos.x)
          let y = Math.min(imgPos.y, startImgPos.y)
          annotation.attrs.width = Math.abs(imgPos.x - startImgPos.x) || 1
          annotation.attrs.height = Math.abs(imgPos.y - startImgPos.y) || 1
          annotation.attrs.x = x + annotation.attrs.width / 2
          annotation.attrs.y = y + annotation.attrs.height / 2
          this.addAnnotation(annotation)
        }
        const up = e => {
          this.sendEvent('annotation-change', {[id]: [annotation]}, 'add')
        }
        openMask(move, up)
      },
      handleDrawLine() {
        let pageIndex = this.getPageIndexByPointerPos()
        let startImgPos = this.getPointerPosOnImage()
        let id = uuid()
        let c = this.pointerConfig[this.pointerType]
        let annotation = {
          pageIndex,
          id,
          relationId: id,
          className: 'line',
          pointerType: this.pointerType,
          createTime: moment().format('YYYY-MM-DD HH:mm:ss'),
          attrs: {
            points: [Math.round(startImgPos.x), Math.round(startImgPos.y)],
            stroke: c.stroke,
            strokeWidth: c.strokeWidth,
            opacity: c.opacity
          }
        }
        const move = e => {
          let viewPos = this.getPointerPosOnView()
          let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
          let p = [Math.round(startImgPos.x), Math.round(startImgPos.y)].concat(Math.round(imgPos.x), Math.round(imgPos.y))
          this.$set(annotation.attrs, 'points', p)
          this.addAnnotation(annotation)
        }
        const up = e => {
          this.sendEvent('annotation-change', {[id]: [annotation]}, 'add')
        }
        openMask(move, up)
      },
      handleDrawFreeLine() {
        let pageIndex = this.getPageIndexByPointerPos()
        let startImgPos = this.getPointerPosOnImage()
        let id = uuid()
        let c = this.pointerConfig[this.pointerType]
        let annotation = {
          pageIndex,
          id,
          relationId: id,
          className: 'line',
          pointerType: this.pointerType,
          createTime: moment().format('YYYY-MM-DD HH:mm:ss'),
          attrs: {
            points: [Math.round(startImgPos.x), Math.round(startImgPos.y)],
            stroke: c.stroke,
            strokeWidth: c.strokeWidth,
            opacity: c.opacity
          }
        }
        // let num = 0
        const move = e => {
          // if (num < 10) {
          //   num++
          //   return
          // }
          // num = 0
          let viewPos = this.getPointerPosOnView()
          let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
          let p = annotation.attrs.points.concat(Math.round(imgPos.x), Math.round(imgPos.y))
          this.$set(annotation.attrs, 'points', p)
          this.addAnnotation(annotation)
        }
        const up = e => {
          this.sendEvent('annotation-change', {[id]: [annotation]}, 'add')
        }
        openMask(move, up)
      },
      handleMoveImage() {
        this.isGrabbing = true
        let scrollTop = this.scrollTop
        let scrollLeft = this.scrollLeft
        let startViewPos = this.getPointerPosOnView()
        let viewPos = startViewPos
        let move = e => {
          viewPos = this.getPointerPosOnView()
          this.scrollTo({
            x: scrollLeft - (viewPos.x - startViewPos.x),
            y: scrollTop - (viewPos.y - startViewPos.y)
          })
        }
        let up = e => {
          this.isGrabbing = false
          if (this.displayMode !== 'single') return;
          let deltaX = viewPos.x - startViewPos.x
          let deltaY = viewPos.y - startViewPos.y
          if (Math.abs(deltaY) > 100) {
            if (deltaY < 0) {
              this.nextPage()
            } else {
              this.prevPage()
            }
            return
          }
          if (Math.abs(deltaX) > 100) {
            if (deltaX < 0) {
              this.nextPage()
            } else {
              this.prevPage()
            }
            return;
          }
        }
        openMask(move, up)
      },
      // handleSelect() {
      //   let A = this.getWord()
      //   if (A) return this.handleSelectText(A)
      //   let viewPos = this.getPointerPosOnView()
      //   let pageIndex = this.getPageIndexByViewPos(viewPos)
      //   if (pageIndex < 0) return
      //   let pageContainer = this.$refs.pageContainer[pageIndex]
      //   let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
      //   if (pageContainer) {
      //     let shape = pageContainer.getIntersection(imgPos)
      //     if (shape) {
      //       // pageContainer.select(shape)
      //     }
      //   }
      //   this.handleSelectShape()
      // },
      // handleSelectShape() {
      //   let startViewPos = this.getPointerPosOnView()
      //   let pageIndex = this.getPageIndexByViewPos(startViewPos)
      //   let imgPos = this.viewPosToImagePos(pageIndex, startViewPos)
      //   let newViewPos = this.imgPosToViewPos(pageIndex, imgPos)
      //   if (startViewPos.x !== newViewPos.x || startViewPos.y !== newViewPos.y) return
      //   let selectrect = document.createElement('div')
      //   selectrect.style.zIndex = 44
      //   selectrect.style.position = 'absolute'
      //   selectrect.style.display = 'inline'
      //   selectrect.style.border = '1px dotted black'
      //   selectrect.style.left = `${this.scrollLeft + startViewPos.x}px`
      //   selectrect.style.top = `${this.scrollTop + startViewPos.y}px`
      //   selectrect.style.width = `${0}px`
      //   selectrect.style.height = `${0}px`
      //   this.$refs.DocumentContainer.appendChild(selectrect)
      //
      //   let x = startViewPos.x
      //   let y = startViewPos.y
      //   let width = ''
      //   let height = ''
      //
      //   let move = e => {
      //     let _viewPos = this.getPointerPosOnView()
      //     let imgPos = this.viewPosToImagePos(pageIndex, _viewPos)
      //     let viewPos = this.imgPosToViewPos(pageIndex, imgPos)
      //
      //     x = Math.min(viewPos.x, startViewPos.x)
      //     y = Math.min(viewPos.y, startViewPos.y)
      //     selectrect.style.left = `${this.scrollLeft + x}px`
      //     selectrect.style.top = `${this.scrollTop + y}px`
      //     width = Math.abs(viewPos.x - startViewPos.x)
      //     height = Math.abs(viewPos.y - startViewPos.y)
      //     selectrect.style.width = `${width}px`
      //     selectrect.style.height = `${height}px`
      //   }
      //   let up = e => {
      //     selectrect.remove()
      //     console.log('此处判断是否相交')
      //     let p1 = this.viewPosToImagePos(pageIndex, {x, y})
      //     let p2 = this.viewPosToImagePos(pageIndex, {x: x + width, y: y + height})
      //     let pageContainer = this.$refs.pageContainer[pageIndex]
      //     pageContainer.selectShapes({x: p1.x, y: p1.y, width: p2.x - p1.x, height: p2.y - p1.y})
      //   }
      //   openMask(move, up)
      // },
      handleSelectText(A) {
        // let viewPos = this.getPointerPosOnView()
        // let pageIndex = this.getPageIndexByViewPos(viewPos)
        // let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
        // let A = this.getWord()
        let move = e => {
          let B = this.getWord(true)
          if (!A) A = B
          if (!B) return
          let rectList = this.getRectListByAToB(A, B)
          rectList.forEach(item => {
            item.type = 'selection-rect'
            item.relationId = 'selection-rect'
            item.id = `selection-rect-${item.id}`
            item.attrs.fill = this.selectionBgColor
          })
          let ids = rectList.map(item => item.id)
          this.clearSelection(ids)
          this.addSelection(...rectList)
        }
        let up = e => {
          if (!this.selectionList.length) return
          if (this.pointerType === 'highlight') {
            return this.selectionListToAnnotation()
          }
          let viewPos = this.getPointerPosOnView()
          let TextPopup = this.$refs.TextPopup
          let x = viewPos.x - TextPopup.offsetWidth / 2
          let y = viewPos.y - TextPopup.offsetHeight - 10
          if (y < 10) y = 10
          // else if (y + TextPopup.offsetHeight > this.viewSize.height - 10) y = this.viewSize.height - TextPopup.offsetHeight - 10
          if (x < 10) x = 10
          else if (x + TextPopup.offsetWidth > this.viewSize.width - 10) x = this.viewSize.width - TextPopup.offsetWidth - 10

          TextPopup.style.left = `${x}px`
          TextPopup.style.top = `${y}px`
          this.TextPopupShow = true
        }
        openMask(move, up)
      },
      getRectListByAToB(A, B) {
        if (!A || !B) return []
        if (A.pageIndex > B.pageIndex || (A.pageIndex === B.pageIndex && A.index > B.index)) [A, B] = [B, A]
        let rowRect = {}
        for (let pageIndex = A.pageIndex; pageIndex <= B.pageIndex; pageIndex++) {
          let words = this.dataList[pageIndex].words
          let start = 0
          let end = words.length - 1
          if (pageIndex === A.pageIndex) start = A.index
          if (pageIndex === B.pageIndex) end = B.index
          for (let i = start; i <= end; i++) {
            let word = words[i]
            // 第一个字
            if (pageIndex === A.pageIndex && i === A.index && A.position === 'right') continue
            // 最后一个字
            if (pageIndex === B.pageIndex && i === B.index && B.position === 'left') continue

            let item = rowRect[`${word.pageIndex}_${word.rowIndex}`]
            if (!item) {
              rowRect[`${word.pageIndex}_${word.rowIndex}`] = {
                startIndex: word.index,
                endIndex: word.index,
                pageIndex: word.pageIndex,
                x: word.x1,
                y: word.y1,
                maxX: word.x2,
                maxY: word.y2,
                text: word.text,
                width: word.x2 - word.x1,
                height: word.y2 - word.y1,
              }
            } else {
              item.x = Math.min(item.x, word.x1)
              item.y = Math.min(item.y, word.y1)
              item.maxX = Math.max(item.maxX, word.x2)
              item.maxY = Math.max(item.maxY, word.y2)
              item.text += word.text
              item.width = item.maxX - item.x
              item.height = item.maxY - item.y
              item.endIndex = word.index
            }
          }
        }
        return Object.keys(rowRect).map(key => {
          let item = rowRect[key]
          return {
            pageIndex: item.pageIndex,
            id: key,
            className: 'rect',
            text: item.text,
            startIndex: item.startIndex,
            endIndex: item.endIndex,
            attrs: {
              x: item.x,
              y: item.y,
              width: item.width,
              height: item.height,
            }
          }
        })
      },
      getWord(force) {
        let viewPos = this.getPointerPosOnView()
        let pageIndex = this.getPageIndexByViewPos(viewPos)
        if (pageIndex < 0) return
        let imgPos = this.viewPosToImagePos(pageIndex, viewPos)
        return this.getWordByImgPos(pageIndex, imgPos, force)
      },
      getWordByWordPos(wordPos) {
        if (/(\d+)-(\d+)/.test(wordPos)) {
          let pageIndex = Number(RegExp.$1)
          let index = Number(RegExp.$2)
          if (!this.dataList[pageIndex]) return
          let words = this.dataList[pageIndex].words
          if (!words || !words.length) return
          return words[index]
        }
      },
      getWordByImgPos(pageIndex, imgPos, force) {
        let words = this.dataList[pageIndex].words
        if (!words || !words.length) return

        for (let i = 0; i < words.length; i++) {
          let word = words[i]
          //字内
          if (imgPos.x >= word.x1 && imgPos.x <= word.x2 && imgPos.y >= word.y1 && imgPos.y <= word.y2) {
            return {
              position: imgPos.x > (word.x1 + word.x2) / 2 ? 'right' : 'left',
              ...word
            }
          }
        }
        if (!force) return
        let prevRowIndex = -1
        let minLineHeight = Number.MAX_VALUE
        for (let i = 0; i < words.length; i++) {
          let word = words[i]
          // 行内
          if (imgPos.y >= word.y1 && imgPos.y <= word.y2) {
            prevRowIndex = word.rowIndex
            break
          } else {
            // 判断最小间隙
            if (prevRowIndex !== word.rowIndex) {
              // 换行了
              if (imgPos.y - word.y2 > 0) {
                // 鼠标上面
                if (imgPos.y - word.y2 < minLineHeight) {
                  minLineHeight = imgPos.y - word.y2
                  prevRowIndex = word.rowIndex
                }
              } else if (word.y1 - imgPos.y > 0) {
                // 鼠标下面
                if (word.y1 - imgPos.y < minLineHeight) {
                  minLineHeight = word.y1 - imgPos.y
                  prevRowIndex = word.rowIndex
                }
              }
            }
          }
        }
        // 文字行prevRowIndex
        let rowWords = words.filter(word => prevRowIndex === word.rowIndex)

        let prevWordIndex = -1
        let minLineWidth = Number.MAX_VALUE

        for (let i = 0; i < rowWords.length; i++) {
          // 字内 // 字的左右之间
          let word = rowWords[i]
          if (imgPos.x >= word.x1 && imgPos.x <= word.x2) {
            return {
              position: imgPos.x > (word.x1 + word.x2) / 2 ? 'right' : 'left',
              ...word
            }
          } else {
            let leftSpace = Math.abs(imgPos.x - word.x1)
            let rightSpace = Math.abs(imgPos.x - word.x2)
            let min = Math.min(leftSpace, rightSpace)
            if (min < minLineWidth) {
              minLineWidth = min
              prevWordIndex = i
            }
          }
        }

        let resWord = rowWords[prevWordIndex]

        if (Math.abs(imgPos.x - resWord.x1) < Math.abs(imgPos.x - resWord.x2)) {
          return {
            position: 'left',
            ...resWord
          }
        } else {
          return {
            position: 'right',
            ...resWord
          }
        }
      },
      handleZoomOverlayClick(e) {
        let type = e.target.dataset.type || e.target.parentElement.dataset.type
        let re = /\d+(\.\d+)?/
        this.setScaleType(re.test(type) ? Number(type) : type)
        this.ZoomOverlayShow = false
      },
      zoomin() {
        let scale = this.scale
        this.setScaleType(scale + 0.1)
      },
      zoomout() {
        let scale = this.scale
        this.setScaleType(scale - 0.1)
      },
      setScaleType(scaleType) {
        let re = /\d+(\.\d+)?/
        this.scaleType = (re.test(scaleType) ? Number(scaleType) : scaleType)
      },
      getPosByPdfMarkingContent(el) {
        const pdfMarkingContent = this.$refs.pdfMarkingContent
        let x = 0
        let y = 0
        do {
          x += el.offsetLeft
          y += el.offsetTop
        }
        while ((el = el.parentElement) && el !== pdfMarkingContent)
        return {x, y}
      },
      toggleZoomOverlay() {
        if (this.ZoomOverlayShow) return this.ZoomOverlayShow = false
        this.ZoomOverlayShow = true
        const pos = this.getPosByPdfMarkingContent(this.$refs.zoomOverlayButton)
        let deltaW = this.$refs.ZoomOverlay.offsetWidth - this.$refs.zoomOverlayButton.offsetWidth
        let scrollLeft = this.$refs.zoomOverlayButton.parentElement.scrollLeft
        this.$refs.ZoomOverlay.style.left = pos.x - (deltaW) / 2 - scrollLeft + 'px'
        this.$refs.ZoomOverlay.style.top = pos.y + this.$refs.zoomOverlayButton.offsetHeight + 'px'
      },
      toggleSearchOverlay() {
        if (this.SearchOverlayShow) return this.SearchOverlayShow = false
        this.SearchOverlayShow = true
      },
      toggleLeftPanel() {
        if (this.LeftPanelShow) return this.LeftPanelShow = false
        this.LeftPanelShow = true
      },
      handleDocumentContainerWheel(e) {
        if (this.stopWheel) return
        this.stopWheel = true
        setTimeout(() => this.stopWheel = false, 500)
        if (this.displayMode === 'single') {
          if (e.wheelDeltaY < 0) {
            this.nextPage()
          } else if (e.wheelDeltaY > 0) {
            this.prevPage()
          }
        }
      },
      handleScroll() {
        this.$nextTick(() => {
          let target = this.$refs.DocumentContainer
          this.scrollTop = target.scrollTop
          this.scrollLeft = target.scrollLeft
        })
      },
      handleDocumentContainerContextmenu(e) {
        let viewPos = this.getPointerPosOnView()
        let ContextMenuPopup = this.$refs.ContextMenuPopup
        let x = viewPos.x - ContextMenuPopup.offsetWidth / 2
        let y = viewPos.y - ContextMenuPopup.offsetHeight - 10
        if (y < 10) y = 10
        // else if (y + ContextMenuPopup.offsetHeight > this.viewSize.height - 10) y = this.viewSize.height - ContextMenuPopup.offsetHeight - 10
        if (x < 10) x = 10
        else if (x + ContextMenuPopup.offsetWidth > this.viewSize.width - 10) x = this.viewSize.width - ContextMenuPopup.offsetWidth - 10

        ContextMenuPopup.style.left = `${x}px`
        ContextMenuPopup.style.top = `${y}px`
        this.ContextMenuPopupShow = true
      },
      handleViewSizeChange(size) {
        this.viewSize = {
          width: size.width - 8,
          height: size.height - 8,
        }
      },
      handleScaleKeyDown(e) {
        if (/\d/.test(e.key)) {
        } else if (/Delete|Backspace|Enter|ArrowUp|ArrowDown|ArrowLeft|ArrowRight/.test(e.key)) {

        } else {
          e.preventDefault()
        }
      },
      handleScaleKeyUp(e) {
        e.target.value = e.target.value.replace(/[^0-9]/g, '')
      },
      handleScaleEnter(ev) {
        let value = ev.target.value
        this.setScaleType(Number(value) / 100)
      },
      handlePageIndexEnter(ev) {
        let value = ev.target.value
        if (Number(value) < 1) value = '1'
        else if (Number(value) > this.dataList.length) value = `${this.dataList.length}`
        this.skipPage(Number(value) - 1)
      },
      scrollTo({x, y}) {
        this.$nextTick(() => {
          let target = this.$refs.DocumentContainer
          if (x !== undefined) target.scrollLeft = x
          if (y !== undefined) target.scrollTop = y
        })
      },
      prevPage() {
        this.skipPage(this.currPageIndex - 1)
      },
      nextPage() {
        this.skipPage(this.currPageIndex + 1)
      },
      skipPage(pageIndex) {
        if (pageIndex < 0 || pageIndex > this.length - 1) return
        if (this.displayMode === 'single') {
          this.currPageIndex = pageIndex
          return;
        }
        let scrollTop = 0
        for (let i = 0; i < pageIndex; i++) {
          let imgSize = this.dataList[i].imgSize
          scrollTop += (imgSize.height * this.scale + 8 * this.scale)
        }
        this.scrollTo({y: scrollTop})
      },
      skipPageByWordPos(wordPos) {
        let A = this.getWordByWordPos(wordPos)
        if (!A) return
        let pageIndex = A.pageIndex
        let scrollTop = 0
        for (let i = 0; i < pageIndex; i++) {
          let imgSize = this.dataList[i].imgSize
          scrollTop += (imgSize.height * this.scale + 8 * this.scale)
        }
        let h = (A.y2 + A.y1) / 2 * this.scale
        let deltaH = this.viewSize.height / 2 - h
        this.scrollTo({y: scrollTop - deltaH})
      },
      getOffsetPos() {
        let offsetTop = 0
        let offsetLeft = 0
        let el = this.$refs.DocumentContainer
        do {
          offsetTop += el.offsetTop
          offsetLeft += el.offsetLeft
        }
        while ((el = el.offsetParent))
        return {offsetLeft, offsetTop}
      },
      getPointerPosOnView(e = event) {
        if (e.changedTouches) e = e.changedTouches[0]
        let offsetPos = this.getOffsetPos()
        let x = e.pageX - offsetPos.offsetLeft
        let y = e.pageY - offsetPos.offsetTop
        if (x < 0) x = 0
        else if (x > this.viewSize.width) x = this.viewSize.width
        if (y < 0) y = 0
        else if (y > this.viewSize.height) y = this.viewSize.height
        return {x, y}
      },
      getPointerPosOnPage(e) {
        let viewPos = this.getPointerPosOnView(e)
        let pageIndex = this.getPageIndexByViewPos(viewPos)
        return this.viewPosToPagePos(pageIndex, viewPos)
      },
      getPointerPosOnImage(e) {
        let viewPos = this.getPointerPosOnView(e)
        let pageIndex = this.getPageIndexByViewPos(viewPos)
        return this.viewPosToImagePos(pageIndex, viewPos)
      },
      viewPosToPagePos(pageIndex, viewPos) {
        let pageSections = this.$refs.pageSection
        if (!pageSections) return {x: 0, y: 0}
        const margin = Math.round(4 * this.scale)
        let imgSize = this.dataList[pageIndex].imgSize
        if (this.displayMode === 'single') pageIndex = 0
        const pageSection = pageSections[pageIndex]
        let x = this.scrollLeft + viewPos.x - pageSection.offsetLeft + margin
        let y = this.scrollTop + viewPos.y - pageSection.offsetTop + margin
        const maxWidth = /*imgSize.width*/this.maxImageWidth * this.scale + margin * 2
        const maxHeight = imgSize.height * this.scale + margin * 2
        if (x < 0) x = 0
        else if (x > maxWidth - 1) x = maxWidth - 1
        if (y < 0) y = 0
        else if (y > maxHeight - 1) y = maxHeight - 1
        return {x, y}
      },
      pagePosToImagePos(pageIndex, pagePos) {
        // let pageSections = this.$refs.pageSection
        // if (!pageSections) return {x: 0, y: 0}
        // const margin = Math.round(4 * this.scale)
        let imgSize = this.dataList[pageIndex].imgSize
        let deltaX = (this.maxImageWidth - imgSize.width) / 2
        let x = pagePos.x / this.scale - deltaX - 4
        let y = pagePos.y / this.scale - 4

        if (x < 0) x = 0
        else if (x > imgSize.width - 1) x = imgSize.width - 1
        if (y < 0) y = 0
        else if (y > imgSize.height - 1) y = imgSize.height - 1

        return {x, y}
      },
      viewPosToImagePos(pageIndex, viewPos) {
        let pagePos = this.viewPosToPagePos(pageIndex, viewPos)
        return this.pagePosToImagePos(pageIndex, pagePos)
      },
      pagePosToViewPos(pageIndex, pagePos) {
        const margin = Math.round(4 * this.scale)
        let pageSections = this.$refs.pageSection
        if (!pageSections) return {x: 0, y: 0}
        if (this.displayMode === 'single') pageIndex = 0
        const pageSection = pageSections[pageIndex]
        let x = pagePos.x + pageSection.offsetLeft - margin - this.scrollLeft
        let y = pagePos.y + pageSection.offsetTop - margin - this.scrollTop
        return {x, y}
      },
      imgPosToPagePos(pageIndex, imgPos) {
        // let pageSections = this.$refs.pageSection
        // if (!pageSections) return {x: 0, y: 0}
        // const margin = Math.round(4 * this.scale)
        let imgSize = this.dataList[pageIndex].imgSize
        let deltaX = (this.maxImageWidth - imgSize.width) / 2
        let x = (imgPos.x + 4 + deltaX) * this.scale
        let y = (imgPos.y + 4) * this.scale
        return {x, y}
      },
      imgPosToViewPos(pageIndex, imgPos) {
        let pagePos = this.imgPosToPagePos(pageIndex, imgPos)
        return this.pagePosToViewPos(pageIndex, pagePos)
      },
      getPageIndexByPointerPos(e) {
        let viewPos = this.getPointerPosOnView(e)
        return this.getPageIndexByViewPos(viewPos)
      },
      getPageIndexByViewPos(viewPos) {
        if (this.displayMode === 'single') return this.currPageIndex
        // let pageSections = this.$refs.pageSection
        // if (!pageSections) return -1
        let margin = 4 * this.scale

        let start = 0
        let end = 0
        let scrollTop = this.scrollTop
        let pageIndex = this.dataList.findIndex((page, idx) => {
          start = end
          // let imgSize = this.dataList[idx].imgSize
          let imgSize = page.imgSize
          end = start + margin + imgSize.height * this.scale + margin

          if (idx === 0) end += this.deltaTop
          if (idx === this.dataList.length - 1) end += this.deltaTop
          // console.log(scrollTop + viewPos.y, start, end)
          return scrollTop + viewPos.y >= start && scrollTop + viewPos.y < end
        })
        // if (pageIndex < 0) pageIndex = 0
        return pageIndex
      },
      getImgBySrc(src) {
        return new Promise((resolve, reject) => {
          const img = new window.Image()
          img.onload = e => resolve(img)
          img.onerror = e => {
            // console.log('图片加载失败了')
          }
          img.src = src
        })
      },
      async loadRes(...args) {
        let res = []
        this.progressOpen = true
        for (let i = 0; i < args.length; i++) {
          let dataItem = args[i]
          let imgSrc = dataItem.imgSrc
          let oWords = dataItem.words
          if (this.dataLoadFn && typeof this.dataLoadFn === 'function') {
            try {
              let res = await this.dataLoadFn({...dataItem, pageIndex: i})
              res || (res = {})
              imgSrc = res.imgSrc || errorImgSrc
              oWords = res.words || []
            } catch (e) {
              imgSrc = errorImgSrc
              oWords = []
            }
          }
          let img = await this.getImgBySrc(imgSrc)
          let words = oWords.map((word, idx) => {
            return {
              ...word,
              x1: Math.min(word.x1, word.x2),
              x2: Math.max(word.x1, word.x2),
              y1: Math.min(word.y1, word.y2),
              y2: Math.max(word.y1, word.y2),
              index: idx,
              pageIndex: i
            }
          })
          res[i] = {
            ...dataItem,
            pageIndex: i,
            imgSrc: imgSrc,
            // img: img,
            imgSize: {
              width: img.naturalWidth,
              height: img.naturalHeight
            },
            words: words
          }
          img = null
          this.loadedProgress = (i + 1) / args.length * 100
        }
        this.progressOpen = false
        this.loadedProgress = 0
        return res
      },
      initData() {
        this.maxImageWidth = 0
        this.minImageHeight = 0
        this.maxImageHeight = 0

        this.dataList = []
        this.scrollHeight = 0
        this.scrollTop = -1
        this.scrollLeft = 0
        this.privateData = {
          scaleType: 'page-fit'
        }
        this.ZoomOverlayShow = false
        // this.currPageIndex = -1
        // this.pointerType = 'select'
        this.annotationList = []
        this.isOnText = false
        this.isOnShape = false
        this.isGrabbing = false
      },
      async open({data, annotationList = []}, notInit = false) {
        /*数据初始化*/
        if (!notInit) this.initData()
        /*数据初始化完成*/
        const dataList = await this.loadRes(...data)
        this.maxImageWidth = Math.max(...dataList.map(item => item.imgSize.width))
        this.minImageHeight = Math.min(...dataList.map(item => item.imgSize.height))
        this.maxImageHeight = Math.max(...dataList.map(item => item.imgSize.height))
        this.dataList = dataList
        this.addAnnotationNotOverflow(...annotationList)

        // let target = this.$refs.DocumentContainer
        await this.$nextTick()
        this.scrollTop = 0
        this.sendEvent('loaded')
      }
    }
  }
</script>
<style lang="scss">
  @import "src/components/Marking/src/pdf-marking";

  .debugger-info {
    pointer-events: none;
    position: absolute;
    top: 47px;
    left: 0;
    z-index: 99;

    &__item {

    }
  }
</style>
